package com.junmeng.libyuv.utils

object YUVUtil {
    /**
     * 将byte转为Int,即由-128到+127变为0到255的范围
     */
    fun byteToInt(byte: Byte): Int {
        return byte.toInt() and 0xff
    }

    /**
     * 将byte转为color数值(此种情况下为灰色)
     */
    fun byteToColor(byte: Byte): Int {
        return byteToColor(byte, byte, byte)
    }

    /**
     *将rgb的各个byte转为color数值
     */
    fun byteToColor(r: Byte, g: Byte, b: Byte): Int {
        val red = byteToInt(r)
        val green = byteToInt(g)
        val blue = byteToInt(b)
        return -0x1000000 or (red shl 16) or (green shl 8) or blue
    }

    /**
     *将argb的各个byte转为color数值
     */
    fun byteToColor(a: Byte, r: Byte, g: Byte, b: Byte): Int {
        val alpha = byteToInt(a)
        val red = byteToInt(r)
        val green = byteToInt(g)
        val blue = byteToInt(b)
        return alpha shl 24 or (red shl 16) or (green shl 8) or blue
    }

    /**
     * y平面转为rgb color
     */
    fun yPlaneToColors(
        yDatas: ByteArray,//y平面字节数组，长度必须为width*height
        width: Int, height: Int //y平面宽高
    ): IntArray? {
        if (yDatas.size != width * height) {
            return null
        }
        val colors = IntArray(width * height)
        for (i in yDatas.indices) {
            colors[i] = byteToColor(yDatas[i])
        }
        return colors
    }

    /**
     * rgb24字节数组转为rgb color
     */
    fun rgb24ToColors(
        rgb24: ByteArray,//rgb24字节数组，长度必须为width*height*3
        width: Int, height: Int //宽高
    ): IntArray? {
        if (rgb24.size != width * height * 3) {
            return null
        }
        val colors = IntArray(width * height)
        var index = 0
        for (i in rgb24.indices step 3) {
            colors[index] = byteToColor(
                rgb24[i + 2],
                rgb24[i + 1],
                rgb24[i]
            )
            index++
        }
        return colors
    }

    /**
     * argb字节数组转为rgb color
     */
    fun argbToColors(
        argb: ByteArray,//argb字节数组，长度必须为width*height*4
        width: Int, height: Int //宽高
    ): IntArray? {
        if (argb.size != width * height * 4) {
            return null
        }
        val colors = IntArray(width * height)
        var index = 0
        for (i in argb.indices step 4) {
            colors[index] = byteToColor(
                argb[i + 3],
                argb[i + 2],
                argb[i + 1],
                argb[i]
            )
            index++
        }
        return colors
    }

    /**
     * 旋转yuv中的y平面
     * 参考自：[YUVi420中Y值旋转代码 - 知乎](https://zhuanlan.zhihu.com/p/387267716)
     */
    fun rotateYPlane(
        src: ByteArray,//y平面数据，大小为width * height
        width: Int, height: Int,//y平面宽高
        degree: Int//顺时针旋转的角度，0,90,180,270
    ): ByteArray? {
        if (width <= 0 || height <= 0) {
            return null
        }
        if (src.size != width * height) {
            return null
        }
        if (degree == 0) {
            return src
        }
        val dst = ByteArray(width * height)
        when (degree) {
            90 -> {
                val dstWidth = height
                val dstHeight = width

                for (i in 0 until height) {
                    for (j in 0 until width) {
                        dst[dstWidth * j + (dstWidth - 1 - i)] = src[j + i * width]
                    }
                }
            }
            180 -> {
                val dstWidth = width
                val dstHeight = height
                for (i in 0 until height) {
                    var index: Int = dstWidth
                    for (j in 0 until width) {
                        dst[--index + (dstHeight - 1 - i) * dstWidth] = src[j + i * width]
                    }
                }
            }
            270 -> {
                val dstWidth = height
                val dstHeight = width
                for (i in 0 until height) {
                    for (j in 0 until width) {
                        dst[dstWidth * (dstHeight - 1 - j) + i] = src[j + i * width]
                    }
                }
            }
            else -> {
                return null
            }
        }
        return dst
    }

}